package gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JLabel;
import java.awt.Font;
import java.util.Vector;

import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.JTable;
import javax.swing.JScrollPane;

import pack.help.Command;
import pack.help.Serial;
import pack.help.TableModel;
import pack.model.Control;
import pack.model.Master;
import pack.model.RealRobot;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class Main extends JFrame {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private JPanel contentPane;
	private JTextField v1Textfield;
	private JTextField v2Textfield;
	private JTable table;
	private final static JButton startButton = new JButton("Start");
	private final static JButton stopButton = new JButton("Stop");
	private JTextField timeTextfield;
	/**
	 * 
	 */
	
	// Rows of the command database
	private static Vector<Command> rows;
	// Rows of the command database
	private static Vector<Command> buffer;
	// Table model for the command database
	private static TableModel tableModel;
	private static Control control;
	private static Master master;
	private static Serial port;
	private static Thread thread;
	private static RealRobot realRobot;
	
	public static int prevSpL, prevSpR;



	// running variable enables and disables giving commands to the uC
	private static volatile boolean running;
	// working variable is a flag showing whether we have a thread already
	private static volatile boolean working;
	// this window contains the simulation
	private static SimWindow simulator;
	private JTable bufferTable;
	private static TableModel bufferTableModel;
	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		
		prevSpL = 255;
		prevSpR = 255;
		
		realRobot = new RealRobot(Color.GREEN);
		control = new Control();
		simulator = new SimWindow();
		
		setRunning(false);
		setWorking(false);
		
		port = new Serial("COM18");
		port.write("reset");
		try {
			Thread.sleep(100);
		} catch (InterruptedException e2) {
			e2.printStackTrace();
		}
		port.write("ping");
		try {
			Thread.sleep(50);
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}
		port.waitForReady();
		master = new Master();
		System.out.println("USB interface inited");
		
		simulator.setVisible(true);
		
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Main frame = new Main();
					frame.setTitle("Commands");
					frame.setVisible(true);
					initCommands();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
		
	}
	
	private static void initCommands(){
		
		Command tmp;
		
		tmp = new Command(1000,1f,1f);
		rows.add(tmp);
		
		tmp = new Command(2000,1f,0.7f);
		rows.add(tmp);	
		
		
		 tmp = new Command(3000,0.7f,0.7f);
		rows.add(tmp);
		
		tmp = new Command(2000,-0.5f,-0.5f);
		rows.add(tmp);	
		 
		
		
		tmp = new Command(3500,1.f,-0.7f);
		rows.add(tmp);
		
		tmp = new Command(2500,1.f,1.f);
		rows.add(tmp);
		
		tmp = new Command(4000,-1.f,-1.f);
		rows.add(tmp);
		
		tmp = new Command(1600,-0.8f,-1f);
		rows.add(tmp);
		
		tmp = new Command(8000,0.7f,1f);
		rows.add(tmp);
		
		tmp = new Command(2000,0.7f,0.7f);
		rows.add(tmp);
		
		tmp = new Command(5000,0.4f,0.7f);
		rows.add(tmp);

		/*
		
		tmp = new Command(2000,0.5f,0.3f);
		rows.add(tmp);
		
		tmp = new Command(1000,0.5f,0.5f);
		rows.add(tmp);
		
		tmp = new Command(2000,0.5f,0.3f);
		rows.add(tmp);
		
		tmp = new Command(1000,0.5f,0.5f);
		rows.add(tmp);
		
		tmp = new Command(2000,0.5f,0.3f);
		rows.add(tmp);
		
		tmp = new Command(1000,0.5f,0.5f);
		rows.add(tmp);
		
		tmp = new Command(2000,0.5f,0.3f);
		rows.add(tmp);
		
		tmp = new Command(1000,0.5f,0.5f);
		rows.add(tmp);
		
		tmp = new Command(2000,0.5f,0.3f);
		rows.add(tmp);
		
		tmp = new Command(1000,0.5f,0.5f);
		rows.add(tmp);
		
		*/
		
		tableModel.fireTableRowsInserted(0, rows.size());
	}

	public static SimWindow getSimulator(){
		return simulator;
	}
	
	public static Control getControl(){
		return control;			
	}
	
	public static Serial getPort(){
		return port;		
	}
	
	// getting the number of waiting commands
	// Number Of Commands
	public static int noCommands(){
		return rows.size();
	}
	
	// function to call when a thread is done working
	static public void done(){
		startButton.setEnabled(true);
		stopButton.setEnabled(false);	
		setWorking(false);
	}
	
	// reading the next command
	public static Command readRow(){
		Command ret = new Command();
		if (rows.size() == 0) return null;
		ret = rows.elementAt(0);
		rows.remove(0);
		tableModel.fireTableRowsDeleted(0, rows.size());
		buffer.add(ret);
		buffer.setSize(2);
		if (buffer.get(1)==null) buffer.setSize(1);
		bufferTableModel.fireTableRowsInserted(0, buffer.size());
		return ret;
	}
	
	public static void shiftBuffer(){
		if (buffer.size() == 2){
			Command tmp = buffer.get(1);
			buffer.clear();
			buffer.add(tmp);
			buffer.setSize(1);
		} else {
			buffer.clear();
		}
		bufferTableModel.fireTableRowsUpdated(0, buffer.size());
	}
	
	public void commitActionListener(){
		
		// alert for an empty input
		if ( v2Textfield.getText().length() == 0 || v1Textfield.getText().length() == 0){
			JOptionPane.showMessageDialog(contentPane, "You must fill the missing information!");
		} else {
			Command newCommand = new Command();
			
			
			// If the input is not a 
			try {
				newCommand.setTime(Integer.parseInt(timeTextfield.getText()));
				newCommand.setV1(Float.parseFloat(v1Textfield.getText()));	
				newCommand.setV2(Float.parseFloat(v2Textfield.getText()));	
				rows.add(newCommand);
			} catch(Exception ex) {
				JOptionPane.showMessageDialog(contentPane, "Wrong number syntax!");			
			}
			
			
		//	speedTextfield.setText("");
		//	distDegreesTextfield.setText("");
			
			
			tableModel.fireTableRowsInserted(0, rows.size());
		}	
	}
	
	public void deleteActionListener(){
		int prevSize = rows.size();
		
		int[] deletedRow = table.getSelectedRows();
		
		if ( deletedRow.length == 0 ){
			JOptionPane.showMessageDialog(contentPane, "No row selected!");
		} else {
			for (int i = 0; i < rows.size() ; i++){
				for (int j = 0; j < deletedRow.length; j++){
					if (i==deletedRow[j]){
						for (int k = 0; k < deletedRow.length; k++){
							deletedRow[k]--;
						}	
						rows.remove(i);
					}					
				}
			}
			tableModel.fireTableRowsDeleted(0, prevSize);
		}		
	}
	
	public void stopActionListener(){
		port.write("stop");
		//port.write("reset");
		stopButton.setEnabled(false);
		startButton.setEnabled(true);
		setRunning(false);
		buffer.clear();
		bufferTableModel.fireTableRowsUpdated(0, 2);
		port.write("ping");
	}
	
	public void startActionListener(){
		stopButton.setEnabled(true);
		startButton.setEnabled(false);
		thread = new Thread(master);
		if (!isWorking())(thread).start();
		setRunning(true);	
	}
	
	public void resetActionListener(){
		port.write("reset");
		stopButton.setEnabled(false);
		startButton.setEnabled(true);
		setRunning(false);
		buffer.clear();
		bufferTableModel.fireTableRowsUpdated(0, 2);
		port.write("ping");
	}
	
	public static boolean isRunning() {
		return running;
	}

	public static void setRunning(boolean running) {
		Main.running = running;
	}

	public static boolean isWorking() {
		return working;
	}

	public static void setWorking(boolean working) {
		Main.working = working;
	}
	
	public static RealRobot getRealRobot() {
		return realRobot;
	}
	
	/**
	 * Create the frame.
	 */
	public Main() {

		// initializing table rows
		rows = new Vector<Command>();
		buffer = new Vector<Command>();
		//initializing talbe model
		tableModel = new TableModel(rows);
		bufferTableModel = new TableModel(buffer);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 514, 658);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		contentPane.setLayout(new BorderLayout(0, 0));
		
		JPanel panel = new JPanel();
		contentPane.add(panel);
		panel.setLayout(null);
		
		JLabel commandInputLabel = new JLabel("Command input");
		commandInputLabel.setFont(new Font("Tahoma", Font.PLAIN, 20));
		commandInputLabel.setBounds(10, 11, 147, 42);
		panel.add(commandInputLabel);
		
		v1Textfield = new JTextField();
		v1Textfield.setFont(new Font("Tahoma", Font.PLAIN, 13));
		v1Textfield.setBounds(172, 65, 94, 32);
		panel.add(v1Textfield);
		v1Textfield.setColumns(10);
		
		JLabel disDegreesLabel = new JLabel("v1 (m/s) (right)");
		disDegreesLabel.setBounds(173, 49, 123, 14);
		panel.add(disDegreesLabel);
		
		v2Textfield = new JTextField();
		v2Textfield.setFont(new Font("Tahoma", Font.PLAIN, 13));
		v2Textfield.setBounds(328, 65, 79, 32);
		panel.add(v2Textfield);
		v2Textfield.setColumns(10);
		
		JLabel lblNewLabel = new JLabel("v2 (m/s) (left)");
		lblNewLabel.setBounds(328, 50, 99, 14);
		panel.add(lblNewLabel);
		
		JButton commitButton = new JButton("Commit");
		
		
		// commitButton action listener for registering a command to the table
		commitButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				commitActionListener();
			}
		});
		commitButton.setBounds(172, 108, 111, 32);
		panel.add(commitButton);
		
		JScrollPane scrollPane = new JScrollPane();
		scrollPane.setBounds(10, 194, 468, 229);
		panel.add(scrollPane);
		
		table = new JTable(tableModel);
		bufferTable = new JTable(bufferTableModel);
		table.setFillsViewportHeight(true);
		scrollPane.setViewportView(table);
		bufferTable.setFillsViewportHeight(true);
		bufferTableModel.fireTableRowsUpdated(0, buffer.size());
		
		
		JButton deleteButton = new JButton("Delete Selected");
		// delete Button action listener for deleting a command from the table
		deleteButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				deleteActionListener();
			}
		});
		deleteButton.setBounds(313, 108, 129, 32);
		panel.add(deleteButton);
		
		
		stopButton.setEnabled(false);
		// startButton action listener for starting giving commands
		startButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				startActionListener();
			}
		});
		startButton.setFont(new Font("Tahoma", Font.PLAIN, 15));
		startButton.setBounds(105, 434, 136, 42);
		panel.add(startButton);
		
		//stopButton action listener for stopping giving commands
		stopButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				stopActionListener();
			}
		});
		stopButton.setFont(new Font("Tahoma", Font.PLAIN, 15));
		stopButton.setBounds(251, 434, 136, 42);
		panel.add(stopButton);
		
		JLabel lblCommandList = new JLabel("Command list");
		lblCommandList.setFont(new Font("Tahoma", Font.PLAIN, 20));
		lblCommandList.setBounds(10, 151, 147, 42);
		panel.add(lblCommandList);
		
		JLabel lblTimems = new JLabel("Time (ms)");
		lblTimems.setBounds(21, 49, 145, 14);
		panel.add(lblTimems);
		
		timeTextfield = new JTextField();
		timeTextfield.setFont(new Font("Tahoma", Font.PLAIN, 13));
		timeTextfield.setColumns(10);
		timeTextfield.setBounds(20, 65, 94, 32);
		panel.add(timeTextfield);
		
		JScrollPane bufferScrollPane = new JScrollPane();
		bufferScrollPane.setBounds(10, 544, 468, 55);
		panel.add(bufferScrollPane);
		
		bufferScrollPane.setViewportView(bufferTable);
		
		JLabel bufferLabel = new JLabel("Buffer");
		bufferLabel.setFont(new Font("Tahoma", Font.PLAIN, 20));
		bufferLabel.setBounds(10, 491, 147, 42);
		panel.add(bufferLabel);
		
		JButton btnNewButton = new JButton("Reset");
		btnNewButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				resetActionListener();
			}
		});
		btnNewButton.setBounds(399, 505, 79, 23);
		panel.add(btnNewButton);
	}
	
	
}
